/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package game.gamemath;

/**
 *
 * @author UtMan
 */
public class vec3
{
    float[] xyz = new float[3];

    public float X()
    {
        return xyz[0];
    }

    public void X(float x)
    {
        xyz[0] = x;
    }

    public float Y()
    {
        return xyz[1];
    }

    public void Y(float y)
    {
        xyz[1] = y;
    }

    public float Z()
    {
        return xyz[2];
    }

    public void Z(float z)
    {
        xyz[2] = z;
    }

    public float[] XYZ()
    {
        return xyz;
    }

    public void XYZ(float[] xyz)
    {
        if(xyz.length < 3 || xyz.length > 3)
        {
            //TODO error check
            return;
        }
        this.xyz = xyz;
    }
    
    public vec3()
    {
        
    }
    
    public vec3(float x, float y, float z)
    {
        xyz[0] = x;
        xyz[1] = y;
        xyz[2] = z;
    }
    
    public vec3(float[] _xyz)
            throws ArrayIndexOutOfBoundsException
    {
        if(_xyz.length != 3)
            throw new ArrayIndexOutOfBoundsException("Invalid vector initialization length - " + _xyz.length);
        xyz[0] = _xyz[0];
        xyz[1] = _xyz[1];
        xyz[2] = _xyz[2];
        
    }

    public vec3 Plus(vec2 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() + rhs.X());
        ret.Y(this.Y() + rhs.Y());
        return ret;
    }

    public vec3 Plus(vec3 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() + rhs.X());
        ret.Y(this.Y() + rhs.Y());
        ret.Z(this.Z() + rhs.Z());
        return ret;
    }

    public vec3 Plus(vec4 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() + rhs.X());
        ret.Y(this.Y() + rhs.Y());
        ret.Z(this.Z() + rhs.Z());
        return ret;
    }

    public vec3 Plus(float rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() + rhs);
        ret.Y(this.Y() + rhs);
        ret.Z(this.Z() + rhs);
        return ret;
    }

    public vec3 Minus(vec2 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() - rhs.X());
        ret.Y(this.Y() - rhs.Y());
        return ret;
    }

    public vec3 Minus(vec3 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() - rhs.X());
        ret.Y(this.Y() - rhs.Y());
        ret.Z(this.Z() - rhs.Z());
        return ret;
    }

    public vec3 Minus(vec4 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() - rhs.X());
        ret.Y(this.Y() - rhs.Y());
        ret.Z(this.Z() - rhs.Z());
        return ret;
    }

    public vec3 Minus(float rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() - rhs);
        ret.Y(this.Y() - rhs);
        ret.Z(this.Z() - rhs);
        return ret;
    }

    public vec3 MulitpliedBy(vec2 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() * rhs.X());
        ret.Y(this.Y() * rhs.Y());
        return ret;
    }

    public vec3 MulitpliedBy(vec3 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() * rhs.X());
        ret.Y(this.Y() * rhs.Y());
        ret.Z(this.Z() * rhs.Z());
        return ret;
    }

    public vec3 MulitpliedBy(vec4 rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() * rhs.X());
        ret.Y(this.Y() * rhs.Y());
        ret.Z(this.Z() * rhs.Z());
        return ret;
    }

    public vec3 MulitpliedBy(float rhs)
    {
        vec3 ret = new vec3();
        ret.X(this.X() * rhs);
        ret.Y(this.Y() * rhs);
        ret.Z(this.Z() * rhs);
        return ret;
    }

    public vec3 DividedBy(vec2 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() / rhs.X());
        ret.Y(this.Y() / rhs.Y());
        return ret;
    }

    public vec3 DividedBy(vec3 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0 || rhs.Z() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() / rhs.X());
        ret.Y(this.Y() / rhs.Y());
        ret.Z(this.Z() / rhs.Z());
        return ret;
    }

    public vec3 DividedBy(vec4 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0 || rhs.Z() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() / rhs.X());
        ret.Y(this.Y() / rhs.Y());
        ret.Z(this.Z() / rhs.Z());
        return ret;
    }

    public vec3 DividedBy(float rhs)
            throws DivideByZeroException
    {
        if(rhs == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() / rhs);
        ret.Y(this.Y() / rhs);
        ret.Z(this.Z() / rhs);
        return ret;
    }

    public vec3 ModBy(vec2 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() % rhs.X());
        ret.Y(this.Y() % rhs.Y());
        return ret;
    }

    public vec3 ModBy(vec3 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0 || rhs.Z() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() % rhs.X());
        ret.Y(this.Y() % rhs.Y());
        ret.Z(this.Z() % rhs.Z());
        return ret;
    }

    public vec3 ModBy(vec4 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0 || rhs.Z() == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() % rhs.X());
        ret.Y(this.Y() % rhs.Y());
        ret.Z(this.Z() % rhs.Z());
        return ret;
    }

    public vec3 ModBy(float rhs)
            throws DivideByZeroException
    {
        if(rhs == 0)
            throw new DivideByZeroException();
        vec3 ret = new vec3();
        ret.X(this.X() % rhs);
        ret.Y(this.Y() % rhs);
        ret.Z(this.Z() % rhs);
        return ret;
    }

    public boolean Equals(vec3 rhs)
    {
        if(this.xyz == rhs.xyz)
            return true;
        return false;
    }

    public void PlusEquals(vec3 rhs)
    {
        this.xyz[0] += rhs.xyz[0];
        this.xyz[1] += rhs.xyz[1];
        this.xyz[2] += rhs.xyz[2];
    }

    public void PlusEquals(float rhs)
    {
        this.xyz[0] += rhs;
        this.xyz[1] += rhs;
        this.xyz[2] += rhs;
    }

    public void MinusEquals(vec3 rhs)
    {
        this.xyz[0] -= rhs.xyz[0];
        this.xyz[1] -= rhs.xyz[1];
        this.xyz[2] -= rhs.xyz[2];
    }

    public void MinusEquals(float rhs)
    {
        this.xyz[0] -= rhs;
        this.xyz[1] -= rhs;
        this.xyz[2] -= rhs;
    }

    public void MultiplyEquals(vec3 rhs)
    {
        this.xyz[0] *= rhs.xyz[0];
        this.xyz[1] *= rhs.xyz[1];
        this.xyz[2] *= rhs.xyz[2];
    }

    public void MultiplyEquals(float rhs)
    {
        this.xyz[0] *= rhs;
        this.xyz[1] *= rhs;
        this.xyz[2] *= rhs;
    }

    public void DivideEquals(vec3 rhs)
            throws DivideByZeroException
    {
        if(rhs.X() == 0 || rhs.Y() == 0 || rhs.Z() == 0)
            throw new DivideByZeroException();
        this.xyz[0] /= rhs.xyz[0];
        this.xyz[1] /= rhs.xyz[1];
        this.xyz[2] /= rhs.xyz[2];
    }

    public void DivideEquals(float rhs)
            throws DivideByZeroException
    {
        if(rhs == 0)
            throw new DivideByZeroException();
        this.xyz[0] /= rhs;
        this.xyz[1] /= rhs;
        this.xyz[2] /= rhs;
    }

    public float Magnitude()
    {
        float mag = 0.0f;
        mag = (float)java.lang.Math.sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]);
        return mag;
    }

    public vec3 Normalize()
    {
        float rsqrt = 1 / Magnitude();
        xyz[0] *= rsqrt;
        xyz[1] *= rsqrt;
        xyz[2] *= rsqrt;
        return this;
    }

    public vec3 Negate()
    {
        xyz[0] = -xyz[0];
        xyz[1] = -xyz[1];
        xyz[2] = -xyz[2];
        return this;
    }

    public static vec3 Zero()
    {
        return new vec3(0, 0, 0);
    }

    public static vec3 Right()
    {
        return new vec3(1, 0, 0);
    }

    public static vec3 Up()
    {
        return new vec3(0, 1, 0);
    }

    public static vec3 Forward()
    {
        return new vec3 (0, 0, 1);
    }

    public static vec3 One()
    {
        return new vec3 (1, 1, 1);
    }
}
